<template>
    <div
        :class="{
            'lego-spec-item': true,
            'lego-spec-item-need-filled': modelValue.specConfig.attrModel.needFilled
        }"
    >
        <div class="lego-spec-item-block-header">
            <span class="lego-spec-item-block-header-handler" @click="changeExpand">
                <el-icon v-if="expandFlag"><ArrowDownBold /></el-icon>
                <el-icon v-else><ArrowUpBold /></el-icon>
                配置字段：{{ modelValue.path }}
            </span>
            <span :display-name="modelValue.spec.displayName || '--'">
                (表单项名称: {{ modelValue.spec.displayName || '--' }})
            </span>
        </div>
        <div v-show="expandFlag">
            <div
                v-if="modelValue.specConfig && modelValue.specConfig.attr && modelValue.specConfig.attr.length"
                class="lego-spec-item-block-body"
            >
                <div class="lego-spec-item-block-title">通用属性</div>
                <template v-for="item in modelValue.specConfig.inAttrList" :key="`${modelValue.path}-${item.key}`">
                    <div class="lego-spec-item-block-row">
                        <div class="lego-spec-item-block-label">{{ item.label || '' }}</div>
                        <div class="lego-spec-item-block-cont">
                            <component
                                :is="componentsMap[item.component]"
                                v-model="modelValue.specConfig.attrModel[item.key]"
                                v-bind="item.attr"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                                @change="handleShowChange(item.key, $event)"
                            />
                            <el-button
                                v-if="isDeletableComponent(item.component)"
                                type="primary"
                                link
                                :icon="Delete"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                                class="delete-btn"
                                @click="deleteConfig(item, 'inAttrList', 'addableAttrList', 'attrModel')"
                            >
                            </el-button>
                        </div>
                    </div>
                </template>
                <div class="lego-spec-item-block-foot">
                    <el-button
                        type="primary"
                        link
                        :icon="Plus"
                        :disabled="refDisabled || !addableAttrDatasource.length"
                        @click="addAttrs(modelValue)"
                    >
                        添加通用属性
                    </el-button>
                </div>
            </div>
            <div
                v-if="
                    modelValue.specConfig && modelValue.specConfig.extraAttr && modelValue.specConfig.extraAttr.length
                "
                class="lego-spec-item-block-body"
            >
                <div class="lego-spec-item-block-title">附加属性</div>
                <template v-for="item in modelValue.specConfig.inExtraAttrList" :key="`${modelValue.path}-${item.key}`">
                    <div class="lego-spec-item-block-row">
                        <div class="lego-spec-item-block-label">{{ item.label || '' }}</div>
                        <div class="lego-spec-item-block-cont">
                            <component
                                :is="componentsMap[item.component]"
                                v-model="modelValue.specConfig.extraAttrModel[item.key]"
                                v-bind="item.attr"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                            />
                            <el-button
                                v-if="isDeletableComponent(item.component)"
                                type="primary"
                                link
                                :icon="Delete"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                                class="delete-btn"
                                @click="deleteConfig(item, 'inExtraAttrList', 'addableExtraAttrList', 'extraAttrModel')"
                                >删除配置
                            </el-button>
                        </div>
                    </div>
                </template>
                <div class="lego-spec-item-block-foot">
                    <el-button
                        type="primary"
                        link
                        :icon="Plus"
                        :disabled="refDisabled || !addableExtraAttrDatasource.length"
                        @click="addExtraAttrs(modelValue)"
                    >
                        添加附加属性
                    </el-button>
                </div>
            </div>
            <div
                v-if="
                    modelValue.specConfig && modelValue.specConfig.rulesList && modelValue.specConfig.rulesList.length
                "
                class="lego-spec-item-block-body"
            >
                <div class="lego-spec-item-block-title">校验规则</div>
                <template v-for="item in modelValue.specConfig.inRulesList" :key="`${modelValue.path}-${item.key}`">
                    <div class="lego-spec-item-block-row">
                        <div class="lego-spec-item-block-label">{{ item.label || '' }}</div>
                        <div class="lego-spec-item-block-cont">
                            <component
                                :is="componentsMap[item.component]"
                                v-model="modelValue.specConfig.rulesModel[item.key]"
                                v-bind="item.attr"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                            />
                            <el-button
                                v-if="isDeletableComponent(item.component)"
                                type="primary"
                                link
                                :icon="Delete"
                                :disabled="refDisabled || (item.attr && item.attr.disabled)"
                                class="delete-btn"
                                @click="deleteConfig(item, 'inRulesList', 'addableRulesList', 'rulesModel')"
                                >删除配置
                            </el-button>
                        </div>
                    </div>
                </template>
                <div class="lego-spec-item-block-foot">
                    <el-button type="primary" link :disabled="refDisabled" :icon="Plus" @click="addRuels(modelValue)">
                        添加校验规则
                    </el-button>
                </div>
            </div>
        </div>
        <div v-show="!expandFlag" class="lego-spec-item-expand-container">
            <el-icon><MoreFilled /></el-icon>
        </div>
        <el-dialog
            title="添加校验规则"
            v-model="rulesOpen"
            :draggable="true"
            :footless="true"
            overlay-class="lego-spec-add-rules-dialog"
            @close="rulesDialogClose"
        >
            <div class="lego-spec-add-rules-dialog-body">
                <div class="lego-spec-add-rules-dialog-row">
                    <div class="lego-spec-add-rules-dialog-label">类别</div>
                    <div class="lego-spec-add-rules-dialog-content">
                        <Select v-model="rulesGroup" :options="groupDatasource" />
                    </div>
                </div>
                <div v-if="rulesGroup" class="lego-spec-add-rules-dialog-row">
                    <div class="lego-spec-add-rules-dialog-label">校验规则</div>
                    <div class="lego-spec-add-rules-dialog-content">
                        <checkbox-group v-model="rulesKey" :items="addableRulesDatasource" />
                    </div>
                </div>
            </div>
            <div class="lego-spec-add-rules-dialog-error">{{ rulesErrorMsg || '' }}</div>
            <div class="lego-spec-add-rules-dialog-footer">
                <el-button type="primary" @click="rulesDialogSubmit">确定</el-button>
                <el-button @click="rulesDialogClose">取消</el-button>
            </div>
        </el-dialog>
        <el-dialog
            title="添加通用属性"
            v-model="attrOpen"
            :draggable="true"
            :footless="true"
            overlay-class="lego-spec-add-rules-dialog"
            @close="attrDialogClose"
        >
            <div class="lego-spec-add-rules-dialog-body">
                <div class="lego-spec-add-rules-dialog-row">
                    <div class="lego-spec-add-rules-dialog-label">通用属性</div>
                    <div class="lego-spec-add-rules-dialog-content">
                        <checkbox-group v-model="attrsKey" :items="addableAttrDatasource" />
                    </div>
                </div>
            </div>
            <div class="lego-spec-add-rules-dialog-error">{{ attrErrorMsg || '' }}</div>
            <div class="lego-spec-add-rules-dialog-footer">
                <el-button type="primary" @click="attrDialogSubmit">确定</el-button>
                <el-button @click="attrDialogClose">取消</el-button>
            </div>
        </el-dialog>
        <el-dialog
            title="添加附加属性"
            v-model="extraAttrOpen"
            :draggable="true"
            :footless="true"
            overlay-class="lego-spec-add-rules-dialog"
            @close="extraAttrDialogClose"
        >
            <div class="lego-spec-add-rules-dialog-body">
                <div class="lego-spec-add-rules-dialog-row">
                    <div class="lego-spec-add-rules-dialog-label">附加属性</div>
                    <div class="lego-spec-add-rules-dialog-content">
                        <checkbox-group v-model="extraAttrsKey" :items="addableExtraAttrDatasource" />
                    </div>
                </div>
            </div>
            <div class="lego-spec-add-rules-dialog-error">{{ extraAttrErrorMsg || '' }}</div>
            <div class="lego-spec-add-rules-dialog-footer">
                <el-button type="primary" @click="extraAttrDialogSubmit">确定</el-button>
                <el-button @click="extraAttrDialogClose">取消</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
import {ref, computed, unref, onMounted} from 'vue';
import {Select, CheckboxGroup, RadioButtonGroup, Textarea} from './basic';
import {ElInput as Input, ElSwitch as Switch, ElInputNumber as NumberInput, ElMessageBox, ElIcon} from 'element-plus';
import CheckboxGroupAdapter from './CheckboxGroupAdapter.vue';
import PresetColors from './PresetColors.vue';
import ActionLinkAdapter from './ActionLinkAdapter.vue';
import RangeAdapter from './RangeAdapter.vue';
import EnumValuesAdapter from './EnumValuesAdapter.vue';
import {Plus, MoreFilled, ArrowDownBold, ArrowUpBold, Delete} from '@element-plus/icons-vue';
import {get, keyBy, filter, each, set, groupBy, includes, startsWith, isArray} from 'lodash-es';
import {Emitter} from 'mitt';

const modelValue = defineModel({
    type: Object,
    required: true
});

const props = defineProps<{
    disabled: Boolean;
    eventBus: Emitter<Record<string, any>>;
}>();

const refDisabled = computed(() => props.disabled);
const expandFlag = ref(true);
const eventBus = props.eventBus;
eventBus.on('showChange', (v) => {
    const {path, value} = v;
    // 父节点被标记删除，子节点就不显示了
    if (startsWith(modelValue.value.path, `${path}.`)) {
        modelValue.value.isShow = value;
    }
});
const groupDatasource = computed(() => modelValue.value?.specConfig?.groupDatasource || []);
const addableRulesDatasource = computed(() => {
    const addableRulesList = modelValue.value?.specConfig?.addableRulesList || [];
    const addableRulesGroup = groupBy(addableRulesList, (it) => it.group);
    const inRulesList = modelValue.value?.specConfig?.inRulesList || [];
    const inRulesKeys = keyBy(inRulesList, 'key');
    const groupValue = unref(rulesGroup);
    let addableGroupRulesList: any[] = [];
    if (groupValue) {
        addableGroupRulesList = addableRulesGroup[groupValue] || [];
    }
    addableGroupRulesList = filter(addableGroupRulesList, (it) => !inRulesKeys[it.key]);
    return addableGroupRulesList.map(({label, key}) => ({label, value: key}));
});
const addableAttrDatasource = computed(() => {
    let addableAttrList = modelValue.value?.specConfig?.addableAttrList || [];
    const inAttrList = modelValue.value?.specConfig?.inAttrList || [];
    const inAttrKeys = keyBy(inAttrList, 'key');
    addableAttrList = filter(addableAttrList, (it) => !inAttrKeys[it.key]);
    return addableAttrList.map(({label, key}) => ({label, value: key}));
});
const addableExtraAttrDatasource = computed(() => {
    let addableExtraAttrList = modelValue.value?.specConfig?.addableExtraAttrList || [];
    const inExtraAttrList = modelValue.value?.specConfig?.inExtraAttrList || [];
    const inExtraAttrKeys = keyBy(inExtraAttrList, 'key');
    addableExtraAttrList = filter(addableExtraAttrList, (it) => !inExtraAttrKeys[it.key]);
    return addableExtraAttrList.map(({label, key}) => ({label, value: key}));
});

const rulesOpen = ref(false);
const attrOpen = ref(false);
const extraAttrOpen = ref(false);
const rulesGroup = ref();
const rulesKey = ref([]);
const attrsKey = ref([]);
const extraAttrsKey = ref([]);
const rulesErrorMsg = ref('');
const attrErrorMsg = ref('');
const extraAttrErrorMsg = ref('');
const addRuels = (spec) => {
    rulesOpen.value = true;
};
const addAttrs = (spec) => {
    attrOpen.value = true;
};
const addExtraAttrs = (spec) => {
    extraAttrOpen.value = true;
};
const rulesDialogSubmit = () => {
    // add rules
    if (!rulesGroup.value) {
        rulesErrorMsg.value = '请选择类别';
    }
    if (!rulesKey.value?.length) {
        rulesErrorMsg.value = '请勾选校验规则';
    }
    const rulesMap = get(unref(modelValue.value), 'specConfig.rulesMap');
    const addRulesKey = unref(rulesKey);
    if (!modelValue.value?.specConfig?.inRulesList?.length) {
        modelValue.value.specConfig.inRulesList = [];
    }
    if (!modelValue.value?.specConfig?.rulesModel) {
        modelValue.value.specConfig.rulesModel = {};
    }
    each(addRulesKey, (key) => {
        modelValue.value.specConfig.inRulesList.push(rulesMap[key]);
        modelValue.value.specConfig.rulesModel[key] = undefined;
    });
    const addableRulesList = filter(
        get(modelValue.value, 'specConfig.addableRulesList', []),
        (item) => !includes(addRulesKey, item.key)
    );
    set(modelValue.value, 'specConfig.addableRulesList', addableRulesList);
    rulesDialogClose();
};
const attrDialogSubmit = () => {
    if (!attrsKey.value?.length) {
        attrErrorMsg.value = '请勾选通用属性';
    }
    const attrMap = get(unref(modelValue.value), 'specConfig.attrMap');
    const addAttrsKey = unref(attrsKey);
    if (!modelValue.value?.specConfig?.inAttrList?.length) {
        console.log('inAttrList is empty');
        modelValue.value.specConfig.inAttrList = [];
    }
    if (!modelValue.value?.specConfig?.attrModel) {
        console.log('attrModel is empty');
        modelValue.value.specConfig.attrModel = {};
    }
    each(addAttrsKey, (key) => {
        console.log(key, attrMap[key]);
        modelValue.value.specConfig.inAttrList.push(attrMap[key]);
        modelValue.value.specConfig.attrModel[key] = undefined;
    });
    const addableAttrList = filter(
        get(modelValue.value, 'specConfig.addableAttrList', []),
        (item) => !includes(addAttrsKey, item.key)
    );
    set(modelValue.value, 'specConfig.addableAttrList', addableAttrList);
    attrDialogClose();
};
const extraAttrDialogSubmit = () => {
    if (!extraAttrsKey.value?.length) {
        extraAttrErrorMsg.value = '请勾选附加属性';
    }
    const extraAttrMap = get(unref(modelValue.value), 'specConfig.extraAttrMap');
    const addExtraAttrsKey = unref(extraAttrsKey);
    if (!modelValue.value?.specConfig?.inExtraAttrList?.length) {
        modelValue.value.specConfig.inExtraAttrList = [];
    }
    if (!modelValue.value?.specConfig?.extraAttrModel) {
        modelValue.value.specConfig.extraAttrModel = {};
    }
    each(addExtraAttrsKey, (key) => {
        modelValue.value.specConfig.inExtraAttrList.push(extraAttrMap[key]);
        modelValue.value.specConfig.extraAttrModel[key] = undefined;
    });
    const addableExtraAttrList = filter(
        get(modelValue.value, 'specConfig.addableExtraAttrList', []),
        (item) => !includes(addExtraAttrsKey, item.key)
    );
    set(modelValue.value, 'specConfig.addableExtraAttrList', addableExtraAttrList);

    extraAttrDialogClose();
};
const rulesDialogClose = () => {
    rulesGroup.value = null;
    rulesKey.value = [];
    rulesOpen.value = false;
};
const extraAttrDialogClose = () => {
    extraAttrsKey.value = [];
    extraAttrOpen.value = false;
};
const attrDialogClose = () => {
    attrsKey.value = [];
    attrOpen.value = false;
};
const componentsMap = {
    Switch,
    Input,
    Select,
    NumberInput,
    Textarea,
    CheckboxGroup,
    RadioButtonGroup,
    CheckboxGroupAdapter,
    PresetColors,
    ActionLinkAdapter,
    RangeAdapter,
    EnumValuesAdapter
};
const changeExpand = () => {
    expandFlag.value = !expandFlag.value;
};
const deleteConfig = (item, inListKey, addableListKey, modelKey) => {
    ElMessageBox.confirm(`您确定要删除[${modelValue.value.path}]节点的『${item.label}』属性？`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消'
    })
        .then(() => {
            const inListData = filter(get(modelValue.value, `specConfig.${inListKey}`), (it) => it.path !== item.path);
            const addableListData = get(modelValue.value, `specConfig.${addableListKey}`);
            addableListData.push(item);
            set(modelValue.value, `specConfig.${inListKey}`, inListData);
            set(modelValue.value, `specConfig.${addableListKey}`, addableListData);
            set(modelValue.value, `specConfig.${modelKey}.${item.key}`, undefined);
        })
        .catch(() => {
            console.log('取消删除');
        });
};

const isDeletableComponent = (componentName) => {
    const deletableComponentsMap = {
        Input,
        NumberInput,
        Textarea,
        Select,
        CheckboxGroup,
        RangeAdapter,
        EnumValuesAdapter
    };
    return !!deletableComponentsMap[componentName];
};

const sendShowEvent = (value) => {
    if (modelValue.value?.spec.dataType === 'LIST') {
        eventBus.emit('showChange', {
            path: `${modelValue.value?.path}[*]`,
            value: value
        });
    } else {
        eventBus.emit('showChange', {
            path: modelValue.value?.path,
            value: value
        });
    }
};

onMounted(() => {
    if (
        modelValue.value?.specConfig.attrModel.needFilled === false ||
        modelValue.value?.specConfig.attrModel.fieldRemove === true ||
        modelValue.value?.spec.multiline === false ||
        modelValue.value?.spec.fieldRemove === true
    ) {
        sendShowEvent(false);
    }
});

const handleShowChange = (key, status) => {
    console.log(key, status);
    if (key === 'needFilled') {
        sendShowEvent(status);
    }
    if (key === 'fieldRemove') {
        sendShowEvent(!status);
    }
    if (key === 'pickEnumValues' && modelValue.value?.spec.dataType === 'ALTERNATIVE' && isArray(status)) {
        const enumValues = modelValue.value?.spec.enumValues || [];
        if (status.length) {
            each(enumValues, (item) => {
                eventBus.emit('showChange', {
                    path: `${modelValue.value?.path}.${item.value}`,
                    value: includes(status, item.value)
                });
            });
        } else {
            // 特殊逻辑，不选的效果就是全选
            each(enumValues, (item) => {
                eventBus.emit('showChange', {
                    path: `${modelValue.value?.path}.${item.value}`,
                    value: true
                });
            });
        }
    }
};
</script>

<style lang="less" scoped>
@import '../css/lib.less';
.lego-spec-item-need-filled {
    background-color: @dls-background-color-info-active;
}
.lego-spec-item {
    padding: 10px;
    &-block-header {
        line-height: 30px;
        font-size: 18px;
        margin-bottom: 10px;
        color: @dls-color-gray-9;
    }
    &-block-header-handler {
        user-select: none;
        cursor: pointer;
        color: @dls-color-gray-11;
        font-weight: 700;
    }
    &-expand-container {
        padding-left: 20px;
        font-size: 24px;
        color: @dls-color-gray-7;
    }
    &-block-body {
        padding-left: 20px;
    }
    &-block-title {
        line-height: 24px;
        font-size: 16px;
        font-weight: 700;
        margin-bottom: 10px;
    }
    &-block-foot {
        padding-left: 235px;
    }
    &-block-row {
        padding-left: 20px;
        display: flex;
        margin-bottom: 10px;
    }
    &-block-label {
        width: 200px;
        line-height: 32px;
        text-align: right;
    }
    &-block-cont {
        flex: 1;
        margin-left: 15px;

        display: flex;
        flex-direction: row;
        align-items: center;
        gap: 10px;
    }
}
.lego-spec-add-rules-dialog {
    &-body {
        margin-bottom: 20px;
    }
    &-row {
        display: flex;
        margin-bottom: 10px;
    }
    &-label {
        width: 120px;
        line-height: 32px;
        text-align: right;
    }
    &-content {
        flex: 1;
        margin-left: 15px;
        .veui-checkbox-group {
            margin-top: 6px;
        }
    }
    &-error {
        margin-bottom: 10px;
        padding-left: 135px;
        color: @dls-color-error-7;
    }
    &-footer {
        .veui-button {
            margin-right: 10px;
        }
    }
}
</style>
